Understanding the problem
While working in a problem with a colleague we came upon a problem in which it was necessary to transform one element into an array of something complex and different. Since this was a pattern that was going to repeat itself, we defined a protocol for that.
The problem itself required us to have a Parser
which would transform some JSON into an array of core data elements. Lets name them Element
and ComplexElement
Our setup
We have a Parser that transforms some Codable
into an array of ComplexObject
.
protocol Parser {
func transform(data: Codable?) -> [ComplexObject]
}
What we want to achieve here is to transform JsonElement
(which is Codable
) into ComplexMessage
(which is ComplexObject
)
struct JsonElement: Codable {
let messages:[String]
}
struct ComplexMessage: ComplexObject {
let message: String
}
The naive approach
We could be tempted to adopt our parser by directly providing the types of the objects we are dealing with like this
struct ElementParser: Parser {
func transform(data: JsonElement?) -> [ComplexMessage] {
return []
}
}
This will fail. The Swift Compiler will throw you an error Type 'ElementParser' does not conform to protocol 'Parser'`.
The basic approach
Let’s then correct our mistake and implement the original protocol as originally intended
struct ElementParser: Parser {
func transform(data: Codable?) -> [ComplexObject] {
return []
}
}
This still does not feel right. We really would like to specify the types of our Codable
and our ComplexObject
associatedtype to the rescue
To achieve this we can use Associated Types or associatedtype
. An associated type is a placeholder with a keyword that can be defined with typealias
when implementing the protocol.
Associated types can have constraints. In our example we just want them to be of type Codable
and ComplexObject
protocol Parser {
associatedtype Input: Codable
associatedtype Output: ComplexObject
func transform(data: Input?) -> [Output]
}
Once we are done with all this we just can implement our Parser
protocol and fill the placeholders defined in the original protocol definition as associatedtype
struct ElementParser: Parser {
typealias Input = JsonElement
typealias Output = ComplexMessage
func transform(data: JsonElement?) -> [ComplexMessage] {
return []
}
}
And that’s it. There is not a lot of magic around associated types. They are just placeholders we can just fill with a typealias
.
Published on August 29, 2020
Tagged with: